/******************************************************************************
 * Copyright (C) 2013 ShenZhen ComTop Information Technology Co.,Ltd
 * All Rights Reserved.
 * 本软件为深圳康拓普开发研制。未经本公司正式书面同意，其他任何个人、团体不得使用、
 * 复制、修改或发布本软件.
 *****************************************************************************/

package com.code.common.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 通用文件工具类
 * <pre>
 * 提供一些针对文件的工具方法
 * </pre>
 * 
 * @author 陈星凌
 * @since TOP4.0
 * @version 2013-1-30 陈星凌 由原TOP系统迁移,合并CommonFileUtil与FileSerializeUtil
 */
public final class FileUtil {

	/** 日志对象 */
	private final static Logger LOGGER = LoggerFactory
			.getLogger(FileUtil.class);

	/**
	 * 构造函数
	 */
	private FileUtil() {
	}

	/**
	 * 写测试结果到文件中
	 * 
	 * @param resultFileName
	 *            结果文件全路径
	 * @param result
	 *            测试结果字符串
	 */
	public static void writeStringToFile(String resultFileName, String result) {
		FileWriter objFileWriter = null;
		File objResultFile = new File(resultFileName);
		try {
			File objParent = objResultFile.getParentFile();
			if (!objParent.exists()) {
				objParent.mkdirs();
			}
			if (!objResultFile.exists()) {
				objResultFile.createNewFile();
			}
			objFileWriter = new FileWriter(objResultFile, true);
			objResultFile.length();
			if (StringUtil.isBlank(result)) {
				objFileWriter.write("\n\n\n");
				return;
			}
			objFileWriter.write(result);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (objFileWriter != null) {
					objFileWriter.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 将文件内容转化为字符串
	 * 
	 * @param fileFullPath
	 *            文件全路径
	 * @return 转化后的字符串
	 * @throws IOException
	 *             异常
	 */
	public static String getStringFromFile(String fileFullPath)
			throws IOException {

		if (fileFullPath == null || "".equals(fileFullPath)) {
			return null;
		}
		File objFile = new File(fileFullPath);
		byte[] byteF = new byte[2048];
		StringBuffer sbMessage = new StringBuffer((int) objFile.length());

		FileInputStream objFileIuputStream = new FileInputStream(objFile);
		while (objFileIuputStream.read(byteF) != -1) {
			sbMessage.append(new String(byteF, "GB2312"));
			byteF = new byte[2048];
		}
		objFileIuputStream.close();
		return sbMessage.toString().replaceAll(new String(new byte[1]), "");
	}

	/**
	 * <pre>
	 * 解压zip格式的压缩文件到当前文件夹
	 * </pre>
	 * 
	 * <p>
	 * zip格式文件解压函数使用说明：
	 * </p>
	 * <br>
	 * 1.文件名后缀是zip的文件并不一定是zip格式文件，zip格式文件的文件是指压缩的方式是zip，即压缩的算法是zip(此算法是免费算法)；<br>
	 * 2.只有是压缩的算法是zip的文件，用此方法才能解压；<br>
	 * 3.此方法只能对最外层的文件进行解压，如果子文件也是压缩文件，不能解压； <br>
	 * 4.如果文件是以rar的压缩算法进行压缩的，此方法不能解压；(rar压缩算法具有版权) <br>
	 * 5.能否正常解压，与压缩文件的文件名后缀没有关系，只与压缩文件采用的压缩算法有关系；<br>
	 * 6.对aaa.zip文件：下一级没有文件夹，只有文件；这种格式比较实用（返回的集合中全是需要的文件的名字） <br>
	 * 7.此方法有很大的局限性，使用的时候，请自己测试，以保证是否能实现你需要的功能。<br>
	 * 
	 * @param zipFullName
	 *            压缩文件绝对路径
	 * @throws Exception
	 *             解压异常
	 * @return 返回下一级目录文件对象集合
	 */
	public static List<File> unZipFile(String zipFullName) throws Exception {
		if (zipFullName == null) {
			throw new Exception("要解压的文件绝对路径为空!");
		}
		File objFile = new File(zipFullName);
		// 如果文件的父路径为null,在new File(null)是，会出现空指针异常
		if (objFile.getParent() == null) {
			throw new Exception("要解压的文件的父路径为空!");
		}
		return unZipFile(zipFullName, objFile.getParent());
	}

	/**
	 * 主函数
	 * 
	 * @param zipFile
	 *            参数
	 * @param sourceFilesDir
	 *            待压缩的文件对象数组
	 * @throws IOException
	 *             异常
	 */
	public static void zipFile(String zipFile, File sourceFilesDir)
			throws IOException {
		zipFile(zipFile, sourceFilesDir.listFiles());
	}

	/**
	 * 主函数
	 * 
	 * @param zipFile
	 *            参数
	 * @param sourceFilesDir
	 *            待压缩的文件对象数组
	 * @throws IOException
	 *             异常
	 */
	public static void zipFile(String zipFile, String sourceFilesDir)
			throws IOException {
		zipFile(zipFile, new File(sourceFilesDir).listFiles());
	}

	/**
	 * 主函数
	 * 
	 * @param zipFile
	 *            参数
	 * @param sourceFiles
	 *            待压缩的文件对象数组
	 * @throws IOException
	 *             异常
	 */
	public static void zipFile(String zipFile, File[] sourceFiles)
			throws IOException {
//		byte byteF[] = new byte[1024];
//		org.apache.tools.zip.ZipOutputStream objZout = new org.apache.tools.zip.ZipOutputStream(
//				new FileOutputStream(zipFile, true));
//		objZout.setEncoding("GBK");
//		for (int i = 0; i < sourceFiles.length; i++) {
//			InputStream objIn = new FileInputStream(
//					sourceFiles[i].getAbsolutePath());
//			org.apache.tools.zip.ZipEntry objEntry = new org.apache.tools.zip.ZipEntry(
//					sourceFiles[i].getName());
//
//			objZout.putNextEntry(objEntry);
//			int iLen = 0;
//			while ((iLen = objIn.read(byteF)) != -1) {
//				objZout.write(byteF, 0, iLen);
//			}
//			objIn.close();
//			objZout.closeEntry();
//		}
//		objZout.close();
	}

	/**
	 * 解压zip格式的压缩文件到指定位置
	 * 
	 * @param zipFullName
	 *            压缩文件绝对路径
	 * @param unZipFullPath
	 *            解压的目标目录
	 * @throws Exception
	 *             解压异常
	 * @return 返回下一级目录文件对象集合
	 */
	public static List<File> unZipFile(String zipFullName, String unZipFullPath)
			throws Exception {

		// 如果解压的目标目录不存在，则建立目录
		File objUnZipFile = new File(unZipFullPath);
		if (!objUnZipFile.exists()) {
			objUnZipFile.mkdirs();
		}
		// 如果压缩文件不存在，则抛出异常
		File objFile = new File(zipFullName);
		if ((!objFile.exists()) && (objFile.length() <= 0)) {
			throw new Exception("要解压的文件不存在!");
		}

		String strPath = null;
		String strGbkName = null;
		String strTempPath = null;
		ZipFile objZipFile = new ZipFile(zipFullName);
		strPath = objUnZipFile.getAbsolutePath();
		Enumeration<ZipEntry> objEnumeration = (Enumeration<ZipEntry>) objZipFile
				.entries();

		ZipEntry objZipEntry = null;
		File objDir = null;
		File objSubDir = null;
		File objChildFile = null;
		int iCount = 0;
		InputStream objInputStream = null;
		BufferedInputStream objBuffInputStream = null;
		FileOutputStream objFileOutputStream = null;
		BufferedOutputStream objBuffOutputStream = null;

		List<File> lstChildFileName = new ArrayList<File>();// 不能确定集合的大小，不好设置集合合理的大小
		System.out.println(new Timestamp(System.currentTimeMillis())
				+ "：开始文件解压！");
		// 遍历压缩文件的实体，
		while (objEnumeration.hasMoreElements()) {
			// 对压缩文件的每一个实体进行处理（即对压缩文件的子文件进行处理）
			objZipEntry = objEnumeration.nextElement();
			strGbkName = objZipEntry.getName();
			if (objZipEntry.isDirectory()) {
				strTempPath = strPath + File.separator + strGbkName;
				objDir = new File(strTempPath);
				objDir.mkdirs();
				continue;
			}
			// 读文件
			objInputStream = objZipFile.getInputStream(objZipEntry);
			objBuffInputStream = new BufferedInputStream(objInputStream);
			strGbkName = objZipEntry.getName();
			strTempPath = strPath + File.separator + strGbkName;

			// 建目录
			String strSubdir = strGbkName;
			for (int i = 0; i < strSubdir.length(); i++) {
				if (strSubdir.substring(i, i + 1).equalsIgnoreCase("/")) {
					String strTemp = strPath + File.separator
							+ strSubdir.substring(0, i);
					objSubDir = new File(strTemp);
					if (!objSubDir.exists()) {
						objSubDir.mkdir();
					}
				}
			}
			// 写文件
			objFileOutputStream = new FileOutputStream(strTempPath);
			objBuffOutputStream = new BufferedOutputStream(objFileOutputStream);
			// 保证每个子文件都是从0的位置开始读写
			iCount = 0;
			while ((iCount = objBuffInputStream.read()) != -1) {
				objBuffOutputStream.write((byte) iCount);
			}
			objBuffInputStream.close();
			objBuffOutputStream.close();
			objFileOutputStream.close();
			objChildFile = new File(strTempPath);
			lstChildFileName.add(objChildFile);
		}
		System.out.println(new Timestamp(System.currentTimeMillis())
				+ "：结束文件解压！");
		return lstChildFileName;
	}

	/**
	 * 解压GZIP文件
	 * 
	 * @param gZipFile
	 *            GZIP文件完整路径（包括文件名）
	 * @param targetFile
	 *            目标文件完整路径（包括文件名）
	 */
	public static void unGZipFile(String gZipFile, String targetFile) {
		try {
			GZIPInputStream objInputStream = new GZIPInputStream(
					new FileInputStream(new File(gZipFile)));
			File objFile = new File(targetFile);
			if (!objFile.exists()) {
				objFile.getParentFile().mkdirs();
			}
			FileOutputStream objFileOutputStream = new FileOutputStream(objFile);
			int iNum = 0;
			byte[] byteBuf = new byte[1024 * 1024];
			while ((iNum = objInputStream.read(byteBuf)) != -1) {
				objFileOutputStream.write(byteBuf, 0, iNum);
			}
			objFileOutputStream.flush();
			objFileOutputStream.close();
			objInputStream.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 压缩GZIP文件
	 * 
	 * @param sourceFile
	 *            解压前的文件完整路径
	 * @param targetZipFile
	 *            GZIP文件完整路径
	 */
	public static void gZipFile(String sourceFile, String targetZipFile) {
		try {
			FileInputStream objInputStream = new FileInputStream(new File(
					sourceFile));
			GZIPOutputStream objFileOutputStream = new GZIPOutputStream(
					new FileOutputStream(new File(targetZipFile)));
			int iNum = 0;
			byte[] byteBuf = new byte[1024 * 1024];
			while ((iNum = objInputStream.read(byteBuf)) != -1) {
				objFileOutputStream.write(byteBuf, 0, iNum);
			}
			objFileOutputStream.close();
			objInputStream.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 序列化对象
	 * 
	 * @param serialFilePath
	 *            序列化对象的保存路径
	 * @param object
	 *            需要序列化得对象
	 */
	public static void serialObject(String serialFilePath, Object object) {
		FileOutputStream objFos = null;
		ObjectOutputStream objOos = null;
		try {
			objFos = new FileOutputStream(serialFilePath);
			objOos = new ObjectOutputStream(objFos);
			objOos.writeObject(object);
			objOos.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (objFos != null) {
				try {
					objFos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			if (objOos != null) {
				try {
					objOos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 读取被序列化得对象
	 * 
	 * @param serialFilePath
	 *            序列化对象的保存路径
	 * @return 序列化对象
	 */
	public static Object deSerialObject(String serialFilePath) {
		FileInputStream objFileInputStream = null;
		ObjectInputStream objIn = null;
		try {
			objFileInputStream = new FileInputStream(serialFilePath);
			objIn = new ObjectInputStream(objFileInputStream);
			return objIn.readObject();
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			return null;
		} finally {
			if (objFileInputStream != null) {
				try {
					objFileInputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			if (objIn != null) {
				try {
					objIn.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 获得缺省的文件路径
	 * 
	 * @return 当前程序的运行目录
	 */
	public static String getUserDir() {
		return System.getProperty("user.dir") + File.separator;
	}

	/**
	 * 将输入流转换为字节数组
	 * 
	 * @param in
	 *            输入流
	 * @return 字节数组
	 */
	public static byte[] serializeFile(InputStream in) {
		byte[] bFileContent = null;
		java.util.zip.ZipOutputStream objZipOS = null;
		ByteArrayOutputStream objBosIn = null;
		ByteArrayOutputStream objBosResult = null;
		try {
			objBosIn = new ByteArrayOutputStream();
			int iCh;
			while ((iCh = in.read()) != -1) {
				objBosIn.write(iCh);
			}
			byte[] bData = objBosIn.toByteArray();
			objBosResult = new ByteArrayOutputStream();
			objZipOS = new java.util.zip.ZipOutputStream(objBosResult);
			ZipEntry objEntry = new ZipEntry("zip");
			objEntry.setSize(bData.length);
			objZipOS.putNextEntry(objEntry);
			objZipOS.write(bData);
			objZipOS.closeEntry();
			bFileContent = objBosResult.toByteArray();
			return bFileContent;
		} catch (IOException e) {
			LOGGER.error("关闭流时出错", e);
			return null;
		} finally {
			closeOutputStream(objZipOS);
			closeOutputStream(objBosIn);
			closeOutputStream(objBosResult);
		}

	}

	/**
	 * 关闭输出流
	 * 
	 * @param os
	 *            输出流
	 */
	private static void closeOutputStream(OutputStream os) {
		if (os != null) {
			try {
				os.close();
			} catch (IOException e) {
				LOGGER.error("关闭流时出错", e);
			}
		}
	}

	/**
	 * 关闭输入流
	 * 
	 * @param os
	 *            输出流
	 */
	private static void closeInputStream(InputStream os) {
		if (os != null) {
			try {
				os.close();
			} catch (IOException e) {
				LOGGER.error("关闭流时出错", e);
			}
		}
	}

	/**
	 * 将通过serializeFile方法转为字节的输入流重新转换为输入流
	 * 
	 * @param fileZipContent
	 *            文件内容
	 * @return 输入流
	 */
	public static InputStream antiSerializeFile(byte[] fileZipContent) {
		byte[] bFileContent = null;
		ByteArrayInputStream objBis = null;
		ZipInputStream objZip = null;
		ByteArrayOutputStream objBaos = null;
		try {
			objBis = new ByteArrayInputStream(fileZipContent);
			objZip = new ZipInputStream(objBis);
			if (objZip.getNextEntry() != null) {
				byte[] byteBuf = new byte[1024];
				int iNum = -1;
				objBaos = new ByteArrayOutputStream();
				while ((iNum = objZip.read(byteBuf, 0, byteBuf.length)) != -1) {
					objBaos.write(byteBuf, 0, iNum);
				}
				bFileContent = objBaos.toByteArray();
				objBaos.flush();
			}
			return new ByteArrayInputStream(bFileContent);
		} catch (IOException e) {
			LOGGER.error("关闭流时出错", e);
			return null;
		} finally {
			closeOutputStream(objBaos);
			closeInputStream(objBis);
			closeInputStream(objZip);
		}
	}

}